package com.xiyuan.smartutils.crypto;

import com.xiyuan.smartutils.reflect.Unsafe;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xiyuan-lgz
 */
@SuppressWarnings("unused")
public class PBKDF2 {
    static {
        Unsafe.init();
    }
    public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
    // 加密加密盐算法
    public static final String PBKDF2_SALT_ALGORITHM = "SHA1PRNG";
    // 默认盐的长度
    private static final int SALT_SIZE = 16;
    private static final Map<String, SecureRandom> randomMap = new HashMap<String, SecureRandom>(1);
    
    /**
     * @param data           需要加密的数据
     * @param salt           加密盐
     * @param iterationCount 迭代此处
     * @param keyLength      长度
     * @return 加密后的字节数组
     */
    public static byte[] getPBKDF2_SHA1(String data, byte[] salt, int iterationCount, int keyLength) {
        try {
            KeySpec spec = new PBEKeySpec(data.toCharArray(), salt, iterationCount, keyLength);
            
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
            return secretKeyFactory.generateSecret(spec).getEncoded();
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * @param len       加密盐长度
     * @param algorithm RNG算法的名称
     * @return byte[]
     */
    public static byte[] getSalt(int len, String algorithm) {
        SecureRandom random = randomMap.get(algorithm);
        if (random == null) {
            try {
                random = SecureRandom.getInstance(algorithm);
                randomMap.put(algorithm, random);
            }
            catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
            
        }
        
        byte[] bytes = new byte[len];
        random.nextBytes(bytes);
        // 将byte数组转换为16进制的字符串
        // String salt = DatatypeConverter.printHexBinary(bytes);
        return bytes;
    }
    
    public static byte[] getSalt() throws NoSuchAlgorithmException {
        return getSalt(SALT_SIZE, PBKDF2_SALT_ALGORITHM);
    }
}
